﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Windows;
using DataProcessing;
namespace Gene.Render
{
    public class Plane3D
    {
        const double WIDTH = 2;
        const double HEIGHT = 1.5;
        public static Point LEFT_BOTTOM = new Point(-1, -0.1);
        public static Point RIGHT_UP = new Point(-1+WIDTH, -0.1+HEIGHT);

        GeometryModel3D _GeometryModel = new GeometryModel3D();

        /// <summary>
        /// 对齐。需要给chromepairdData的currentwindow赋值时候使用。
        /// </summary>
        public long Alignment
        {
            get;
            set;
        }
        public GeometryModel3D GeometryModel
        {
            get { return _GeometryModel; }
            set { _GeometryModel = value; }
        }
        MeshGeometry3D _MeshGeometry3D = new MeshGeometry3D();

        public double Z
        {
            get;set;
            
        }
        public Brush Drawer
        {
            set;
            get;
        }
        public ChromeDataImg Image;

        public void AddTo(Model3DGroup modelGroup)
        {
            Build();
            modelGroup.Children.Add(_GeometryModel);
        }
        
        public void Build()
        {
       

            // Create a collection of vertex positions for the MeshGeometry3D. 
            Point3DCollection myPositionCollection = new Point3DCollection();
            Int32Collection myTriangleIndicesCollection = new Int32Collection();

            
            BuildRectangle(0,LEFT_BOTTOM,RIGHT_UP, myPositionCollection, myTriangleIndicesCollection);

            _MeshGeometry3D.Positions = myPositionCollection;
            _MeshGeometry3D.TriangleIndices = myTriangleIndicesCollection;

            // Apply the mesh to the geometry model.
            _GeometryModel.Geometry = _MeshGeometry3D;

            // Create a collection of texture coordinates for the MeshGeometry3D.
            PointCollection myTextureCoordinatesCollection = new PointCollection();
            myTextureCoordinatesCollection.Add(new Point(0, 0));
            myTextureCoordinatesCollection.Add(new Point(1, 0));
            myTextureCoordinatesCollection.Add(new Point(1, 1));
            myTextureCoordinatesCollection.Add(new Point(0, 1));

            _MeshGeometry3D.TextureCoordinates = myTextureCoordinatesCollection;

            // Define material and apply to the mesh geometries.
            EmissiveMaterial myMaterial = new EmissiveMaterial(Drawer);
            _GeometryModel.Material = myMaterial;
            
        }

        private void BuildRectangle(int index,Point leftBottom,Point rightUp, Point3DCollection myPositionCollection, Int32Collection myTriangleIndicesCollection)
        {

            myPositionCollection.Add(new Point3D(leftBottom.X,leftBottom.Y, Z));
            myPositionCollection.Add(new Point3D(rightUp.X, leftBottom.Y, Z));
            myPositionCollection.Add(new Point3D(rightUp.X, rightUp.Y, Z));
            myPositionCollection.Add(new Point3D(leftBottom.X,rightUp.Y, Z));

            // Create a collection of triangle indices for the MeshGeometry3D.
            int index0 = index*4;
            int index1 = index0+1;
            int index2 = index0+2;
            int index3 = index0+3;
            myTriangleIndicesCollection.Add(index0);
            myTriangleIndicesCollection.Add(index1);
            myTriangleIndicesCollection.Add(index2);

            myTriangleIndicesCollection.Add(index2);
            myTriangleIndicesCollection.Add(index3);
            myTriangleIndicesCollection.Add(index0);

            myTriangleIndicesCollection.Add(index0);
            myTriangleIndicesCollection.Add(index3);
            myTriangleIndicesCollection.Add(index2);

            myTriangleIndicesCollection.Add(index2);
            myTriangleIndicesCollection.Add(index1);
            myTriangleIndicesCollection.Add(index0);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        public void DrawData(ChromePairData data)
        {
            uint[] accumulations = data.GetAccumulations();

           
            //Image.Draw(accumulations, colors[data.Number % 4]);
            
            //Drawer = new ImageBrush(Image.RenderImage);
            if (accumulations.Length != ChromePairData.RESOLUTION)
            {
                throw new Exception("error!");
            }
            _backUpIndeces = new List<int>();
            _backUpPoints = new List<Point3D>();
            int nonZeroLines = 0;
            for (int i = 0; i < accumulations.Length; i++)
            {
                if (accumulations[i] == 0)
                    continue;
                
                DrawLine(accumulations[i], i,nonZeroLines);
                nonZeroLines++;
            }
          


        }
        public void ToScreenModel(Color color)
        {
            _MeshGeometry3D.Positions.Clear();
            _MeshGeometry3D.TriangleIndices.Clear();
            foreach (Point3D pt in _backUpPoints)
            {
                _MeshGeometry3D.Positions.Add(pt);
            }

            for (int j = 0; j < _backUpIndeces.Count; j++)
            {
                _MeshGeometry3D.TriangleIndices.Add(_backUpIndeces[j]);
            }
            _GeometryModel.Material = new EmissiveMaterial(new SolidColorBrush(color));
        }
        
        List<Point3D> _backUpPoints;
        List<Int32> _backUpIndeces;
        
        const double MAX_Y_FOR_DRAW = 0.5;
        void DrawLine(double accumulation, int position,int lineIndex)
        {
            double yMax = ChromePairData.ALL_CurrentAccumulation_Max;
            double lineWidth = WIDTH / ChromePairData.RESOLUTION;
            double scaleY = accumulation / yMax * MAX_Y_FOR_DRAW;
            double y = scaleY * HEIGHT;
            if (y == double.NaN)
                return;
            Point leftBottom = new Point(LEFT_BOTTOM.X + position * lineWidth, LEFT_BOTTOM.Y);
            Point rightUp = new Point(leftBottom.X + lineWidth, leftBottom.Y + y);
            Point3DCollection myPointCollection = new Point3DCollection();
            Int32Collection myTriangleIndicesCollection = new Int32Collection();
            BuildRectangle(lineIndex, leftBottom, rightUp, myPointCollection, myTriangleIndicesCollection);
            foreach (Point3D pt in myPointCollection)
            {
                _backUpPoints.Add(pt);
            }

            for (int j = 0; j < myTriangleIndicesCollection.Count; j++)
            {
                _backUpIndeces.Add(myTriangleIndicesCollection[j]);
            }


        }

    }
}
